// Copyright (c) Microsoft Corporation. 
// Licensed under the MIT license.

#include "SAllowMorphTargetsMeshView.h"
#include "LODRecipe.h"
#include "SAllowMorphTargetsWidget.h"
#include "AssetRegistryModule.h"

FSkeletalMeshItem::FSkeletalMeshItem(TSoftObjectPtr<class USkeletalMesh> InSkeletalMesh)
	: SkeletalMesh(InSkeletalMesh)
{
	FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
	const FName ObjectPath = InSkeletalMesh.ToSoftObjectPath().GetAssetPathName();
	FAssetData AssetData = AssetRegistryModule.Get().GetAssetByObjectPath(ObjectPath);
	
	NumMorphTargets = AssetData.GetTagValueRef<int32>(TEXT("MorphTargets"));
}

void SAllowMorphTargetsMeshView::Construct(const FArguments& /*Args*/, const TSharedRef<SAllowMorphTargetsWidget> Owner)
{
	OwnerWidget = Owner;
	bIsActiveTimerRegistered = false;
	OnPropertyChangedDelegateHandle = FCoreUObjectDelegates::OnObjectPropertyChanged.AddSP(this, &SAllowMorphTargetsMeshView::OnPropertyChanged);

	RebuildSkeletalMeshList();

	SkeletalMeshListView =
		SNew(SListView<FSkeletalMeshItemPtr>)
		.SelectionMode(ESelectionMode::Single)
		.ListItemsSource(&SkeletalMeshListItems)
		.OnGenerateRow(this, &SAllowMorphTargetsMeshView::OnGenerateRow)
		.OnSelectionChanged(this, &SAllowMorphTargetsMeshView::OnSelectionChanged)
		;

	ChildSlot
		[
			SNew(SVerticalBox)
			/*+ SVerticalBox::Slot()
			.AutoHeight()
			[
				SNew(STextBlock)
				.Text(FText::FromString(TEXT("Select Skeletal Mesh:")))
				.Font(FCoreStyle::GetDefaultFontStyle("Bold", 10))
			]*/
		+SVerticalBox::Slot()
		.FillHeight(1.0f)
		[
			SkeletalMeshListView.ToSharedRef()
		]

		];
}

SAllowMorphTargetsMeshView::~SAllowMorphTargetsMeshView()
{
	FCoreUObjectDelegates::OnObjectPropertyChanged.Remove(OnPropertyChangedDelegateHandle);
	OnPropertyChangedDelegateHandle.Reset();
}

void SAllowMorphTargetsMeshView::Refresh()
{
	if (!bIsActiveTimerRegistered)
	{
		bIsActiveTimerRegistered = true;
		RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SAllowMorphTargetsMeshView::TriggerRefreshSkeletalMeshList));
	}
}

EActiveTimerReturnType SAllowMorphTargetsMeshView::TriggerRefreshSkeletalMeshList(double /*InCurrentTime*/, float /*InDeltaTime*/)
{
	RebuildSkeletalMeshList();

	bIsActiveTimerRegistered = false;
	return EActiveTimerReturnType::Stop;
}

void SAllowMorphTargetsMeshView::RebuildSkeletalMeshList()
{
	ULODRecipe* LODRecipe = OwnerWidget.Pin()->GetLODRecipe();
	const auto& SkeletalMeshes = LODRecipe->GetSkeletalMeshes();

	SkeletalMeshListItems.Reset();
	SkeletalMeshListItems.Reserve(SkeletalMeshes.Num());
	for (const auto& SkelMesh : SkeletalMeshes)
	{
		SkeletalMeshListItems.Add(MakeShareable(new FSkeletalMeshItem(SkelMesh)));
	}

	// Update the list widget
	if (SkeletalMeshListView.IsValid())
	{
		SkeletalMeshListView->RequestListRefresh();
	}
}

// Called when a property on the specified object is modified
void SAllowMorphTargetsMeshView::OnPropertyChanged(UObject* ObjectBeingModified, FPropertyChangedEvent& PropertyChangedEvent)
{
	if (ULODRecipe* LODRecipe = Cast<ULODRecipe>(ObjectBeingModified))
	{
		const FName PropertyName(PropertyChangedEvent.Property->GetFName());
		if (PropertyName == GET_MEMBER_NAME_CHECKED(ULODRecipe, SkeletalMeshes))
		{
			Refresh();
		}
	}
}

FSkeletalMeshItemPtr SAllowMorphTargetsMeshView::GetSelectedSkeletalMesh() const
{
	if (SkeletalMeshListView.IsValid())
	{
		auto SelectedItems = SkeletalMeshListView->GetSelectedItems();
		if (SelectedItems.Num() > 0)
		{
			const auto& SelectedSkeletalMeshItem = SelectedItems[0];
			return SelectedSkeletalMeshItem;
		}
	}

	return NULL;
}

TSharedRef<ITableRow> SAllowMorphTargetsMeshView::OnGenerateRow(FSkeletalMeshItemPtr Item, const TSharedRef<STableViewBase>& OwnerTable)
{
	FString NumMorphTargets = FString::Format(TEXT("({0})"), { Item->GetNumMorphTargets() });

	return
		SNew(STableRow<FSkeletalMeshItemPtr>, OwnerTable)
		[
			SNew(SHorizontalBox)
			+ SHorizontalBox::Slot()
			.HAlign(EHorizontalAlignment::HAlign_Left)
			.Padding(4.0f)
			[
				SNew(STextBlock)
				.Text(FText::FromString(Item->GetSkeletalMesh().GetAssetName()))
				.Font(FCoreStyle::GetDefaultFontStyle("Regular", 10))
			]
			+ SHorizontalBox::Slot()
			.HAlign(EHorizontalAlignment::HAlign_Right)
			.Padding(4.0f)
			[
				SNew(STextBlock)
				.Text(FText::FromString(NumMorphTargets))
				.Font(FCoreStyle::GetDefaultFontStyle("Regular", 10))
			]
		];
}

void SAllowMorphTargetsMeshView::OnSelectionChanged(FSkeletalMeshItemPtr Item, ESelectInfo::Type /*SelectInfo*/)
{
	OwnerWidget.Pin()->OnSkeletalMeshSelectionChanged();
}